import Foundation
import libsrt

/// An actor for writing interpolated string messages to srt logging system.
public actor SRTLogger {
    /// The singleton logger instance.
    public static let shared = SRTLogger()

    public enum Level: Sendable {
        /// Highly detailed and very frequent messages.
        case debug
        /// Occasionally displayed information.
        case notice
        /// Unusual behavior.
        case warning
        /// Abnormal behavior
        case error
        /// Error that makes the current socket unusabl
        case crit

        var value: Int32 {
            switch self {
            case .debug:
                return LOG_DEBUG
            case .notice:
                return LOG_NOTICE
            case .warning:
                return LOG_WARNING
            case .error:
                return LOG_ERR
            case .crit:
                return LOG_CRIT
            }
        }
    }

    /// Constants that indicate the addition to levels the logging system has functional areas.
    public enum FunctionalArea: Int32, Sendable {
        /// General uncategorized log, for serious issues only
        case general = 0
        /// Socket create/open/close/configure activities
        case bstats = 1
        /// Connection establishment and handshake
        case control = 2
        /// The checkTimer and around activities
        case data = 3
        /// The TsBPD thread
        case tsbpd = 4
        /// System resource allocation and management
        case rsrc = 5
        /// Haicrypt module area
        case haicrypt = 6
        /// Congestion control module
        case congest = 7
        /// Packet filter module
        case pfilter = 8
        /// Applications
        case applog
        /// API part for socket and library managmenet
        case apiCtrl = 11
        /// Queue control activities
        case queCtrl = 13
        /// EPoll, internal update activities
        case epollUpd = 16
        /// API part for receiving
        case apiRecv = 21
        /// Buffer, receiving side
        case bufRecv = 22
        /// Queue, receiving side
        case queRecv = 23
        /// CChannel, receiving side
        case chanRecv = 24
        /// Group, receiving side
        case grpRecv = 25
        /// API part for sending
        case apiSend = 31
        /// Buffer, sending side
        case bufSend = 32
        /// Queue, sending side
        case queSend = 33
        /// CChannel, sending side
        case chnSend = 34
        /// Group, sending side
        case grpSend = 35
        /// Internal activities not connected directly to a socket
        case `internal` = 41
        /// Queue, management part
        case queMgmt = 43
        /// CChannel, management part
        case chnMgmt = 44
        /// Group, management part
        case grpMgmt = 45
        /// EPoll, API part
        case epollApi = 46

        func addLogFA() {
            srt_addlogfa(rawValue)
        }

        func delLogFA() {
            srt_dellogfa(rawValue)
        }
    }

    private init() {
        srt_setloglevel(level.value)
    }

    /// The current logging level.
    public private(set) var level: Level = .notice {
        didSet {
            guard level != oldValue else {
                return
            }
            srt_setloglevel(level.value)
        }
    }

    /// The current logging functional areas.
    public private(set) var functionalAreas: Set<FunctionalArea> = [] {
        didSet {
            for area in oldValue.subtracting(functionalAreas) {
                area.delLogFA()
            }
            for area in functionalAreas.subtracting(oldValue) {
                area.addLogFA()
            }
        }
    }

    /// Sets the current logging level.
    public func setLevel(_ level: Level) {
        self.level = level
    }

    /// Sets the current logging functional areas.
    public func setFunctionalAreas(_ functionalAreas: Set<FunctionalArea>) {
        self.functionalAreas = functionalAreas
    }
}
